package com.pzhuweb.sgblog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pzhuweb.sgblog.domain.dto.ArticleDto;
import com.pzhuweb.sgblog.domain.entity.Article;
import com.pzhuweb.sgblog.domain.entity.ArticleTag;
import com.pzhuweb.sgblog.domain.entity.Category;
import com.pzhuweb.sgblog.domain.enums.AppHttpCodeEnum;
import com.pzhuweb.sgblog.domain.vo.*;
import com.pzhuweb.sgblog.exception.SystemException;
import com.pzhuweb.sgblog.mapper.ArticleMapper;
import com.pzhuweb.sgblog.service.ArticleService;
import com.pzhuweb.sgblog.service.ArticleTagService;
import com.pzhuweb.sgblog.service.CategoryService;
import com.pzhuweb.sgblog.domain.utils.BeanCopyUtils;
import com.pzhuweb.sgblog.domain.utils.RedisCache;
import com.pzhuweb.sgblog.domain.utils.SystemConstants;
import com.pzhuweb.sgblog.domain.utils.ResponseResult;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {


    @Resource
    @Lazy
    private CategoryService categoryService;

    @Resource
    private RedisCache redisCache;

    @Resource
    private ArticleTagService articleTagService;

    @Override
    public ResponseResult<?> hotArticle() {
        // 查询热门文章，封装成 ResponseResult 返回

        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        // 必须是正式文章，不能是被删除的文章(逻辑删除)
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);  // 0表示已发布正式文章
        // 降序排列
        queryWrapper.orderByDesc(Article::getViewCount);

        // 最多查询10条
        Page<Article> page = new Page<>(1, 10);
        page(page, queryWrapper);
        List<Article> articles = page.getRecords();

        // 对BeanCopy的封装
        List<HotArticleVo> hotArticleVos = BeanCopyUtils.copyBeanList(articles, HotArticleVo.class);
        return new ResponseResult<>().ok(hotArticleVos);
    }

    @Override
    public ResponseResult<?> articleList(Integer pageNum, Integer pageSize, Long categoryId) {

        // 查询条件，已发布的文章、置顶的文章排在最前面(对置顶字段进行降序)
        LambdaQueryWrapper<Article> articleLambdaQueryWrapper = new LambdaQueryWrapper<>();

        // 如果不是首页分类列表里面要查询文章，则会传入categoryId，即只能查询这个分类列表里面的对应文章
        // 当 categoryId!=null&&categoryId>0 这个条件满足时，才会把后面两个参数带到SQL里面
        articleLambdaQueryWrapper.eq(categoryId != null && categoryId > 0, Article::getCategoryId, categoryId);

        // 已发布的文章
        articleLambdaQueryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);

        // 指定以isTop字段进行降序排序
        articleLambdaQueryWrapper.orderByDesc(Article::getIsTop);
        // 分页查询
        Page<Article> page = new Page<>(pageNum, pageSize);
        page(page, articleLambdaQueryWrapper);

        List<Article> articles = page.getRecords();
//         根据article查询category的id
        for (Article article : articles) {
            Long cId = article.getCategoryId();
            Category categoryServiceById = categoryService.getById(cId);
            article.setCategoryName(categoryServiceById.getName());
        }
        // 封装查询结果
        List<ArticleLIstVo> articleLIstVos = BeanCopyUtils.copyBeanList(page.getRecords(), ArticleLIstVo.class);

        PageVo pageVo = new PageVo(articleLIstVos, page.getTotal());
        return ResponseResult.okResult(pageVo);
    }

    @Override
    public ResponseResult<?> getArticlesDetail(Long id) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getId, getById(id));
        // 根据id查询文章详情
        Article article = getById(id);

        // 从redis中获取viewCount
        Integer cacheMapValue = redisCache.getCacheMapValue(SystemConstants.VIEW_COUNT, id.toString());
        article.setViewCount(cacheMapValue.longValue());

        //转换为vo
        ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class);
        // 根据分类id查询分类名
        Category category = categoryService.getById(articleDetailVo.getCategoryId());
        if (category != null) {
            articleDetailVo.setCategoryName(category.getName());

        }
        // 封装文章详情返回
        return ResponseResult.okResult(articleDetailVo);
    }


    /*
     *
     * ①在应用启动时把博客的浏览量存储到redis中
     * ②更新浏览量时去更新redis中的数据
     * ③每隔10分钟把Redis中的浏览量更新到数据库中
     * ④读取文章浏览量时从redis读取
     * */
    @Override
    public ResponseResult<?> updateViewCount(Long id) {
        // 更新浏览量时去更新redis中的数据
        redisCache.incrementCacheMapValue(SystemConstants.VIEW_COUNT, id.toString(), 1);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult<?> addArticle(ArticleDto articleDto) {
        // 根据文章id 连表 标签id
        Article article = BeanCopyUtils.copyBean(articleDto, Article.class);
        save(article);

        // 用tagId和articleId创建ArticleTag对象，然后把对象添加到集合再批量保存
        List<ArticleTag> articleTagList = articleDto.getTags().stream()
                .map(tagId -> new ArticleTag(article.getId(), tagId)).toList();
        articleTagService.saveBatch(articleTagList);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult<?> getList(Integer pageNum, Integer pageSize, String title, String summary) {
        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(title), Article::getTitle, title)
                .like(StringUtils.hasText(summary), Article::getSummary, summary);
        // 对文章分页查询
        Page<Article> articlePage = new Page<>(pageNum, pageSize);
        page(articlePage, wrapper);
        PageVo pageVo = new PageVo(articlePage.getRecords(), articlePage.getTotal());
        return ResponseResult.okResult(pageVo);
    }

    @Override
    public ResponseResult<?> getArticle(Long id) {
        Article article = getById(id);
        if (Objects.isNull(article)) {
            throw new SystemException(AppHttpCodeEnum.SYSTEM_ERROR);
        }
        // 联查tagId
        LambdaQueryWrapper<ArticleTag> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ArticleTag::getArticleId, id);
        List<ArticleTag> articleTags = articleTagService.list(wrapper);
        List<Long> tagList = articleTags.stream()
                .map(ArticleTag::getTagId).toList();
        ArticleVo articleVo = BeanCopyUtils.copyBean(article, ArticleVo.class);
        articleVo.setTags(tagList);
        return ResponseResult.okResult(articleVo);
    }

    @Override
    public ResponseResult<?> updateArticle(ArticleVo articleVo) {
        Article article = BeanCopyUtils.copyBean(articleVo, Article.class);
        LambdaUpdateWrapper<Article> wrapper = new LambdaUpdateWrapper<>();
        // 更新文章
        wrapper.eq(Article::getId, articleVo.getId());
        update(article, wrapper);
        // 更新标签,先删除原有标签，再保存新的标签
        LambdaQueryWrapper<ArticleTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArticleTag::getArticleId,articleVo.getId());
        articleTagService.remove(queryWrapper);
        List<ArticleTag> articleTags = articleVo.getTags().stream()
                .map(tagId -> new ArticleTag(articleVo.getId(), tagId)).toList();
        articleTagService.saveBatch(articleTags);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult<?> deleteArticleByIds(List<Long> id) {
        removeBatchByIds(id);
        return ResponseResult.okResult();
    }
}
